#include <iostream>
#include <string>
using namespace std;
class MyException
{
public:
	MyException(string msg)
	{
		cout << "创建了异常对象" << endl;
		this->msg = msg;
	}
	//拷贝构造函数
	MyException(const MyException& e)
	{
		this->msg = e.msg + "--" + e.msg;
		cout << "拷贝构造函数创建对象" << endl;
	}
	string get_msg()
	{
		return this->msg;
	}
	~MyException()
	{
		cout << "对象析构" + this->msg << endl;
	}
private:
	string msg;
};
/*
异常接口声明:
1）为了加强程序的可读性，可以在函数声明中列出可能抛出的所有异常类型，例如：
void func() throw (A, B, C , D); //这个函数func（）能够且只能抛出类型A B C D及其子类型的异常。
2）如果在函数声明中没有包含异常接口声明，则次函数可以抛掷任何类型的异常，例如：
void func();
3）一个不抛掷任何类型异常的函数可以声明为：
void func()  throw();
4） 如果一个函数抛出了它的异常接口声明所不允许抛出的异常，unexpected函数会被调用，该函数默认行为调用terminate函数中止程序。

/结论：C++编译器通过throw 来产生对象，C++编译器再执行对应的catch分支，相当于一个函数调用，把实参传递给形参。
*/
double divide(int a, int b)throw(int, MyException, MyException*)//声明要抛出的异常类型(声明后只能抛该类型或者子类的异常),引用和类型不能同时用，推荐用引用
{
	if (b == 0)
	{
		throw a;
	}
	else if (b < 0)
	{
		MyException e("除数不能为负数"); //抛类类型的异常，会再执行两次拷贝构造函数
		cout << "抛异常" << endl;
		throw e;
	}
	else if (b > 0)
	{

		MyException *pe = new MyException("除数大于0");//抛指针类型的异常不会再另外创建对象,捕获到异常进行处理后，销毁该异常对象，释放内存
		throw pe;
	}
	cout << "发生异常后改行不会执行" << endl;
	return a / b;
}
int main3()
{
	try
	{
		divide(20, -5);
	}
	catch (int e)//e可以写也可以不写
	{

		cout << e << " 除零了" << endl;
	}
	catch (MyException e)
	{
		cout << "捕获到异常了" << endl;
		cout << e.get_msg() << endl;
	}
	catch (MyException *e)
	{
		cout << e->get_msg() << endl;
		//异常处理后，销毁对象
		delete(e);
	}
	catch (...)
	{
		cout << "未知的异常" << endl;
	}
	return 0;
}